<script lang="ts">
	import { createEventDispatcher } from "svelte";
	const dispatch = createEventDispatcher();

	// 控制上传模式：false 为单文件上传，true 为文件夹上传
	let uploadModeFolder = false;

	// 存储构建好的目录树对象
	let directoryTree = {};

	/**
	 * 处理文件输入变化事件
	 * 单文件上传和文件夹上传都会触发该事件，
	 * 如果是文件夹上传，则利用文件对象的 webkitRelativePath 构建目录树
	 */
	function handleInput(event: Event) {
		const input = event.target as HTMLInputElement;
		const files = input.files;
		console.log(files);
		if (!files || files.length === 0) return;

		// 当为文件夹上传模式时，构建目录树并转换成类似 tree 命令的格式字符串
		if (uploadModeFolder) {
			directoryTree = buildDirectoryTree(Array.from(files));
			const treeStr = treeToString(directoryTree);
			localStorage.setItem(
			'tree',
			JSON.stringify(treeStr)
		);
			console.log("Directory Tree:\n" + treeStr);
		}

		// 遍历每个文件，读取内容并派发上传事件
		Array.from(files).forEach(file => {
			const reader = new FileReader();
			reader.onloadend = () => {
				if (!reader.result) return;
				const src = reader.result.toString();
				// 对每个文件触发一次上传事件，父组件会按照单文件逻辑处理
				dispatch("upload", { src, fileName: file.name });
			};
			reader.readAsDataURL(file);
		});
	}

	/**
	 * 根据文件列表构建目录树结构
	 * 每个文件的 webkitRelativePath 属性包含其相对于所选文件夹的路径信息
	 * @param files 选中的文件列表
	 * @returns 构建好的目录树对象
	 */
	function buildDirectoryTree(files: File[]) {
		const tree = {};
		files.forEach(file => {
			// 获取文件的相对路径；若没有则使用文件名
			const relativePath = file.webkitRelativePath || file.name;
			const parts = relativePath.split('/');
			let current = tree;
			parts.forEach((part, index) => {
				if (index === parts.length - 1) {
					// 最后一部分为文件名，将文件存入 files 数组
					if (!current.files) {
						current.files = [];
					}
					current.files.push({
						name: part,
						file: file
					});
				} else {
					// 中间部分为目录名
					if (!current[part]) {
						current[part] = {};
					}
					current = current[part];
				}
			});
		});
		return tree;
	}

	/**
	 * 将构建好的目录树对象转换为类似 Linux tree 命令格式的字符串
	 * @param tree 目录树对象
	 * @param prefix 用于缩进的前缀
	 * @returns 目录树格式的字符串
	 */
	function treeToString(tree: any, prefix = ''): string {
		let lines: string[] = [];

		// 处理文件列表
		if (tree.files) {
			const fileCount = tree.files.length;
			tree.files.forEach((fileObj, index) => {
				const connector = (index === fileCount - 1 && Object.keys(tree).filter(k => k !== 'files').length === 0)
					? "└── "
					: "├── ";
				lines.push(prefix + connector + fileObj.name);
			});
		}

		// 处理子目录（排除 files 属性）
		const dirs = Object.keys(tree).filter(key => key !== 'files');
		const dirCount = dirs.length;
		dirs.forEach((dir, index) => {
			const connector = (index === dirCount - 1) ? "└── " : "├── ";
			lines.push(prefix + connector + dir);
			// 根据当前节点是最后一个目录来决定前缀
			const newPrefix = prefix + ((index === dirCount - 1) ? "    " : "│   ");
			lines.push(treeToString(tree[dir], newPrefix));
		});

		return lines.join('\n');
	}
</script>

<div class="space-y-4">
	<!-- 模式切换控件：勾选后启用文件夹上传模式 -->
	<label class="flex items-center space-x-2">
		<input type="checkbox" bind:checked={uploadModeFolder} />
		<span>启用文件夹上传模式</span>
	</label>

	<!-- 根据模式显示不同的文件输入 -->
	{#if uploadModeFolder}
		<!-- 文件夹上传：webkitdirectory 属性允许用户选择整个文件夹（注意兼容性问题） -->
		<input
			type="file"
			on:change={handleInput}
			webkitdirectory
			multiple
			data-testid="folder-upload"
			class="focus:border-blue-700 focus:ring-0"
		/>
	{:else}
		<!-- 单文件上传 -->
		<input
			type="file"
			on:change={handleInput}
			data-testid="file-upload"
			class="focus:border-blue-700 focus:ring-0"
		/>
	{/if}
</div>
